﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml;
using System.Windows.Forms;

namespace MicroLink.StsDev2008AddIn.DeploymentFiles
{
    internal class FeatureBuilder
    {
        private FeatureBuilder() { }

        internal static void Update(
            string projectPath,
            string buildPath,
            string targetName)
        {
            //Assembly targetAssembly = Assembly.LoadFile(projectPath + buildPath + @"\" + targetName + ".dll");
            Assembly targetAssembly = Assembly.Load(File.ReadAllBytes(buildPath + @"\" + targetName + ".dll"));
            string assemblyFullName = targetAssembly.FullName;
            targetAssembly = null;

            //Search for any dwp, webpart, feature, or element files to ensure the correct assembly is being used.
            UpdateXmlFiles(assemblyFullName, projectPath, buildPath);
        }

        private static void UpdateXmlFiles(string targetAssembly, string directory, string buildPath)
        {
            UpdateDWPs(targetAssembly, directory);
            UpdateWebParts(targetAssembly, directory);
            UpdateFeature(targetAssembly, directory, buildPath);
            UpdateElement(targetAssembly, directory);

            foreach (string childDirectory in Directory.GetDirectories(directory))
            {
                UpdateXmlFiles(targetAssembly, childDirectory, buildPath);
            }
        }

        private static void UpdateElement(string targetAssembly, string directory)
        {
            foreach (string file in Directory.GetFiles(directory, "*.xml"))
            {
                XmlDocument elementDoc = new XmlDocument();
                elementDoc.Load(file);
                bool fileDirty = false;

                XmlNamespaceManager ns = new XmlNamespaceManager(elementDoc.NameTable);
                ns.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint");

                if (elementDoc.DocumentElement.Name == "Elements")
                {
                    XmlNode assembly = elementDoc.SelectSingleNode(@"//Assembly", ns);
                    if (assembly != null && !targetAssembly.StartsWith(assembly.InnerText))
                    {
                        DialogResult result = MessageBox.Show("Assembly " +
                            assembly.InnerText +
                            " is not the current assembly.\r\n" +
                            "Would you like to update the Element Event Receiver assembly with the current assembly information?",
                            "Element Event Assembly - Current Assembly Mismatch",
                            MessageBoxButtons.YesNo);
                        if (result == DialogResult.Yes)
                        {
                            assembly.InnerText = targetAssembly;
                            fileDirty = true;
                        }
                    }

                    XmlNode control = elementDoc.SelectSingleNode(@"//Control", ns);
                    if (control != null && control.Attributes["ControlAssembly"] != null)
                    {
                        if (control.Attributes["ControlAssembly"].Value != targetAssembly)
                        {
                            DialogResult result = MessageBox.Show("Assembly " +
                            assembly.InnerText +
                            " is not the current assembly.\r\n" +
                            "Would you like to update the Control Assembly with the current assembly information?",
                            "Control Assembly - Current Assembly Mismatch",
                            MessageBoxButtons.YesNo);
                            if (result == DialogResult.Yes)
                            {
                                control.Attributes["ControlAssembly"].Value = targetAssembly;
                                fileDirty = true;
                            }
                        }
                    }

                    XmlNode workflow = elementDoc.SelectSingleNode(@"//Workflow", ns);
                    if (workflow != null)
                    {
                        if (workflow.Attributes["CodeBesideAssembly"].Value != targetAssembly)
                        {
                            DialogResult result = MessageBox.Show("Assembly " +
                            assembly.InnerText +
                            " is not the current assembly.\r\n" +
                            "Would you like to update the Workflow Code Beside Assembly with the current assembly information?",
                            "Workflow Code Beside Assembly - Current Assembly Mismatch",
                            MessageBoxButtons.YesNo);
                            if (result == DialogResult.Yes)
                            {
                                control.Attributes["ControlAssembly"].Value = targetAssembly;
                                fileDirty = true;
                            }
                        }
                    }

                    if(fileDirty)
                        elementDoc.Save(file);
                }
            }
        }

        private static void UpdateFeature(string targetAssembly, string directory, string buildPath)
        {
            string tempdir = directory + "\\";
            if (!tempdir.EndsWith(buildPath))
            {
                foreach (string file in Directory.GetFiles(directory, "*.xml"))
                {
                    XmlDocument featureDoc = new XmlDocument();
                    featureDoc.Load(file);

                    if (featureDoc.DocumentElement.Name == "Feature")
                    {
                        if (featureDoc.DocumentElement.Attributes["ReceiverAssembly"] != null)
                        {
                            if (!targetAssembly.StartsWith(featureDoc.DocumentElement.Attributes["ReceiverAssembly"].Value))
                            {
                                DialogResult result = MessageBox.Show("Assembly " +
                                    featureDoc.DocumentElement.Attributes["ReceiverAssembly"].Value +
                                    " is not the current assembly.\r\n" +
                                    "Would you like to update the Receiver Assembly with the current assembly information?",
                                    "Receiver Assembly - Assembly Mismatch",
                                    MessageBoxButtons.YesNo);
                                if (result == DialogResult.Yes)
                                {
                                    featureDoc.DocumentElement.Attributes["ReceiverAssembly"].Value = targetAssembly;
                                    try
                                    {
                                        featureDoc.Save(file);
                                    }
                                    catch
                                    {
                                    }
                                }
                            }
                        }
                        //featureDoc.Save(file);
                        featureDoc = null;
                    }
                }
            }
        }

        private static void UpdateWebParts(string targetAssembly, string directory)
        {
            foreach (string file in Directory.GetFiles(directory, "*.webpart"))
            {
                XmlDocument webpartDoc = new XmlDocument();
                webpartDoc.Load(file);

                XmlNamespaceManager ns = new XmlNamespaceManager(webpartDoc.NameTable);
                ns.AddNamespace("sp", "http://schemas.microsoft.com/WebPart/v3");

                if (webpartDoc.DocumentElement.Name == "webParts")
                {
                    XmlNode typeNode = webpartDoc.SelectSingleNode(@"//sp:type", ns);
                    if (!typeNode.Attributes["name"].Value.Contains(targetAssembly))
                    {
                        DialogResult result = MessageBox.Show("Assembly " + typeNode.Attributes["name"].Value +
                            " is not the current assembly.\r\n" +
                            "Would you like to update this webpart files with the current assembly information?",
                            "Assembly - Type Node Mismatch", MessageBoxButtons.YesNo);
                        if (result == DialogResult.Yes)
                        {
                            string[] typeComponents = typeNode.Attributes["name"].Value.Split(new char[] { ',' });
                            typeNode.Attributes["name"].Value = string.Format("{0}, {1}", typeComponents[0], targetAssembly);
                            webpartDoc.Save(file);
                        }
                    }
                    //webpartDoc.Save(file);
                    webpartDoc = null;
                }
            }
        }

        private static void UpdateDWPs(string targetAssembly, string directory)
        {
            foreach (string file in Directory.GetFiles(directory, "*.dwp"))
            {
                XmlDocument dwpDoc = new XmlDocument();
                dwpDoc.Load(file);

                XmlNamespaceManager ns = new XmlNamespaceManager(dwpDoc.NameTable);
                ns.AddNamespace("sp", "http://schemas.microsoft.com/WebPart/v2");

                if (dwpDoc.DocumentElement.Name == "WebPart")
                {
                    XmlNode node = dwpDoc.SelectSingleNode(@"//sp:Assembly", ns);
                    if (!targetAssembly.StartsWith(node.InnerText))
                    {
                        DialogResult result = MessageBox.Show("Assembly " + node.InnerText +
                            " is not the current assembly.\r\n" +
                            "Would you like to update this dwp with the assembly information?",
                            "Assembly - Assembly Node Mismatch", MessageBoxButtons.YesNo);
                        if (result == DialogResult.Yes)
                        {
                            node.InnerText = targetAssembly;
                            dwpDoc.Save(file);
                        }
                    }
                    //dwpDoc.Save(file);
                    dwpDoc = null;
                }
            }
        }
    }
}
